#ifndef __TEXTURE_H__
#define __TEXTURE_H__
#include <memory>
#include <map>
#include <vec4.h>
#include <filesystem>

enum class Warp {
    REPEAT,
    MIRROR_REPEAT,
    CLAMP_TO_EDGE
};

class Texture {
public:
    Texture(Warp w = Warp::REPEAT)
        : mWarp(w), mWidth(0), mHeight(0), mChannel(0) { }    
    Texture(Texture&& other) noexcept
        : mMipmap(std::move(other.mMipmap)),
          mWidth(other.mWidth), mHeight(other.mHeight), 
          mChannel(other.mChannel), mWarp(other.mWarp) {}
    Texture& operator = (Texture&& other) noexcept {
        mMipmap  = std::move(other.mMipmap);
        mWidth   = other.mWidth;
        mHeight  = other.mHeight;
        mChannel = other.mChannel;
        mWarp    = other.mWarp;
        return *this;
    }
    Texture(const Texture&) = delete;
    Texture& operator = (const Texture&) = delete;

    void createTexture(const std::string& path);

    Color4f simple(float u, float v, float level = 2.0f) const;
    Color4f nearestSimple(float u, float v) const;
    Color4f bilinearSimple(float u, float v) const;
    Color4f trilinearSimple(float u, float v, float mipmapLevel) const;
private:
    Color4f bilinearLevelSimple(float u, float v, int mipmapSize) const;
    Color4f getTexel(int x, int y, int mipmapSize) const;

    void repeat(int& x, int& y, int mipmapSize) const;
    void mirrorRepeat(int& x, int& y, int mipmapSize) const;
    void clampToEdge(int& x, int& y, int mipmapSize) const;
private:
    std::map<int, std::unique_ptr<unsigned char[]>> mMipmap;
    int mWidth, mHeight, mChannel;
    Warp mWarp;
};

#endif